package com.javaspeak.concurrency.pattern.actor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.BlockingQueue;

import org.apache.log4j.Logger;

/**
 * @author John Dickerson
 */
public class ProcessMethodsRunnable implements Runnable {

	public Logger logger = Logger.getLogger( ProcessMethodsRunnable.class );

	volatile boolean keepRunning = true;

	private final BlockingQueue<MethodRequest> methodRequestBlockingQueue;


	public ProcessMethodsRunnable(
			BlockingQueue<MethodRequest> methodRequestBlockingQueue ){

		this.methodRequestBlockingQueue = methodRequestBlockingQueue;
	}


	public void run() {

		while ( keepRunning ){

			try {
                MethodRequest methodRequest = methodRequestBlockingQueue.take();

                BlockingQueue<MethodResponse> methodResponseBlockingQueue =
                	methodRequest.getMethodResponseBlockingQueue();

                try {
                	Method method = methodRequest.getMethod();

                	Object object = methodRequest.getObject();

                	// logger.debug( "object class = " +
                	//		object.getClass().toString() );

                    Object response =
                    	method.invoke( object, methodRequest.getArgs() );

                    if ( methodResponseBlockingQueue != null ) {

                    	methodResponseBlockingQueue.put(
                    			new MethodResponse( response ) );
                    }
                }
                catch ( InvocationTargetException e ) {

                	if ( methodResponseBlockingQueue != null ) {

                		methodResponseBlockingQueue.put(
                			new MethodResponse( ( Exception )e.getCause() ) );
                    }
                	else {
                        logger.error( e );
                    }
                }
                catch ( Exception e ) {
                    if ( methodResponseBlockingQueue != null ) {

                    	methodResponseBlockingQueue.put(
                    			new MethodResponse( e ) );
                    }
                    else {
                    	logger.error( e );
                    }
                }
            }
			catch ( InterruptedException e ) {

				keepRunning = false;
            }
        }
	}
}
